#include "sExecute.h"

#include <stdlib.h>
#include <sstream>
#include <stdio.h>

#include <Poco/DOM/Document.h>
#include <Poco/DOM/NodeIterator.h>
#include <Poco/Base64Encoder.h>
#include <Poco/Base64Decoder.h>
#include <Poco/StreamCopier.h>
#include "server/net/sData.h"
#include "misc/Interface.h"
#include "misc/Debug.h"
#include "server/net/NetworkControl.h"
/*********************************************************/
void sExecute::execute()
{
	Interface& interface = Interface::Instance();
	NetworkControl& nc = NetworkControl::Instance();

	// This is a bit fishy, since we use a custom interface ( with ncurses ) we can't just let a shell command
	// dump output to the interface... what we do is basicly pipeline the command output to a stream & capture that 
	// stream to output to our interface
	std::string data;
	FILE *stream;
	char buffer[MAX_BUFFER];

	// do it
	stream = popen(cmd.c_str(), "r");
	while ( fgets(buffer, MAX_BUFFER, stream) != NULL )
	data.append(buffer);
	pclose(stream);

	int exitcode = system( cmd.c_str() );
	interface << "Executing: " << cmd << std::endl;
	interface.flush();
	Debug::Instance() << "executed shell command: " << cmd << std::endl;

	// Return the result to the client! 
	sData	response;
	response.setShell(true);
	response.setOrder(0);
	response.setData(data);
	nc.sendTo(&response, getSenderAddr().toString());

	ack();
}
/*********************************************************/
std::string sExecute::serialize() const
{
	NetworkControl& ns = NetworkControl::Instance();
	std::ostringstream		xml;
	std::ostringstream		cmdstr;

	// The command needs to be a multiple of 6 bits ( due to base 64 encoding )
	std::string cmd_ = cmd;
	while ( ((cmd_.length()*8) % 6) != 0 ) {
		cmd_.append("\n");
	}

	// We encode the command into a Base64 string so we can pass it without worrying about possible collisions with xml tags
	Poco::Base64Encoder	encoder(cmdstr);
	encoder << cmd_;

	// Build the xml string for this job
	id = ns.getID();
	xml << "<GS id='" << id << "'>";
	xml << "<Execute>";
	xml << "<cmd>" << cmdstr.str() << "</cmd>";
	xml << "</Execute>";
	xml << "</GS>";

	return( xml.str() );
}
/*********************************************************/
void sExecute::deserialize(Poco::XML::NodeIterator& it)
{
	Poco::XML::Node* node = it.nextNode();
	if ( node->nodeName() != "cmd" ) 
		throw(std::logic_error("Node type execute given, data field 'cmd' missing or incorrectly ordered!"));

	// Decode the command string from a Base64 representation
	std::ostringstream	ostr;
	std::istringstream	istr;
	
	// Decode the result
	istr.str(node->innerText());			// Pass it into a inputstringstream
	Poco::Base64Decoder	decoder(istr);		// decode it...

	// Copy the decoded command to the local storage
	Poco::StreamCopier::copyStream(decoder, ostr);
	std::string result = ostr.str();

	// Remove any appended newlines to align for base 64 encoding
	for ( unsigned int i=0; i<result.length(); i++ ) {
		if ( result[i] == '\n' ) {
			result.erase(i,1);
			i = 0;	
		}
	}

	// Store the command
	cmd = result;
}
/*********************************************************/
std::string sExecute::getCommand() const
{
	return( cmd );
}
/*********************************************************/
void sExecute::setCommand(std::string cmd)
{
	sExecute::cmd = cmd;
}
